Nuxt 的 plugins
有分為 「VueComponent 實例」、「Nuxt context」以及「整合至兩者」的三種不同類型的 plugin,今天除了介紹 Nuxt plugin 的寫法之外,另外看看我們可以怎麼改寫 axios
讓 API 更好使用!
基本就是 Vue 原生寫法:
plugins
底下新增 plugin (vueLog.js),並且引入 Vue。import Vue from 'vue';
install
第一個參數 Vue
是自動注入的。const vueLog = {
install (Vue, options) {
const image = (options && options.image)
? options.image
: 'https://member.ithome.com.tw/avatars/132702?s=ithelp';
const consoleCSS = `line-height: 30px; background:url("${image}"); background-size:cover;`;
Vue.prototype.vueLog = logData => {
console.group('%c ', consoleCSS, 'Vue APP: ');
console.log(logData);
console.groupEnd();
};
}
}
Vue.use
掛載 plugin。import Vue from 'vue';
import vueLog from '../helpers/vueLog';
Vue.use(vueLog, {});
nuxt.config.js
的 plugins
加入 plugin。// ...
plugins: [
'@/plugins/vueLog'
],
// ...
this.vueLog
使用 plugin。若 plugin 單純只要加在 Nuxt context 供 Nuxt 使用,則步驟如下:
在 plugins
底下新增 plugin (nuxtLog.js)
撰寫 plugin,其中第一個參數 context
是自動注入的。
export default (context) => {
context.nuxtLog = logData => {
console.group('Nuxt APP: ');
console.log(logData);
console.groupEnd();
};
};
nuxt.config.js
的 plugins
加入 plugin。// ...
plugins: [
'@/plugins/nuxtLog'
],
// ...
context.nuxtLog
使用 plugin。如果 plugin 同時在 VueComponent 與 Nuxt 中使用,可以依下列步驟建立。
在 plugins
底下新增 plugin (log.js)
撰寫 plugin,兩個參數 context
與 inject
都是自動注入的。
export default (context, inject) => {
inject('log', (logData) => {
const image = 'https://member.ithome.com.tw/avatars/132702?s=ithelp';
const consoleCSS = `line-height: 30px; background:url("${image}"); background-size:cover;`;
console.group('%c ', consoleCSS, 'APP: ');
console.log(logData);
console.groupEnd();
});
}
nuxt.config.js
的 plugins
加入 plugin。// ...
plugins: [
'@/plugins/log'
],
// ...
使用上都跟前面 Vue plugin 以及 Nuxt plugin 相同,有兩點要注意:
this.$log
context.app
底下使用結果:
在了解怎麼寫 plugin 之後,我們來寫個 axios 的 wraper 吧!
npm i lara-validator --save
在專案中增加 configs
資料夾 (可以用 GIT Submodule),並擺放之前為了生成 FormRequest 的 JSON 檔案
建立 plugin (api.js)
import { LaraValidator } from 'lara-validator';
// 驗證 API request body
const validate = (data, rules) => {
if (rules && data) {
const validator = new LaraValidator(rules, data);
const isValid = validator.valid();
if (!isValid) {
const error = new Error('Front end validate error');
error.number = 422;
error.validateError = validator.errorMessage;
throw error;
}
}
};
// 遍歷要轉為 FormData 的 object
const parsingObject = (formData, data, parentKey) => {
const isCurlyBracketsObject = data && typeof data === 'object' && !(data instanceof Date) && !(data instanceof File);
if (isCurlyBracketsObject) {
Object.keys(data).forEach(key => {
const nextParentKey = (parentKey) ? `${parentKey}[${key}]` : key;
parsingObject(formData, data[key], nextParentKey);
});
} else {
const value = data || '';
formData.append(parentKey, value);
}
};
// 將 object 轉為 FormData
const objectToFormData = (data) => {
const formData = new FormData();
parsingObject(formData, data);
return formData;
};
// 呼叫 API
const invokeAPI = async (method, uri, data, token) => {
const headers = {
Authorization: `Bearer ${token}`,
};
switch (method) {
case 'get':
return (await axios.get(uri, { headers })).data;
case 'post':
return (await axios.post(uri, data, { headers })).data;
case 'form':
data = objectToFormData(data);
return (await axios.post(uri, data, { headers })).data;
}
};
// plugin
export default ({ store }, inject) => {
inject('api', async (method, url, data, validator) => {
const token = store.getters.userToken;
try {
validate(data, validator);
return await invokeAPI(method, url, data, token);
} catch (error) {
// do something
}
});
}
在上面 api plugin 的例子當中,呼叫 API 之前會先透過 validator
參數驗證 request data,接著我們將常用的 axios
進一步的打包,包括在 request headers 當中加入 token,另外我們也將 get
、post
以及「以 FormData
作為 request data 的 post
」整合在一起。這樣在使用上可以免去不斷引入各項資料之外,另外當 API 需要傳送檔案的時候也比較方便。
下面是 post 編輯頁使用 api plugin 的範例:
import { validators: { AccessPostByIdRequest, EditPostRequest } } from '../../configs/post';
export default {
name: 'index',
data() {
return {
post: undefined,
};
},
methods: {
async updatePost() {
try {
await this.$api('post', '/v1/post/edit', EditPostRequest.body, this.post);
} catch (error) {
// ...
}
}
},
async asyncData({ app, params }) {
let post = undefined;
try {
const getPostByIdData = { postId: params['id'] };
const { data } = await app.$api('post', '/v1/post', AccessPostByIdRequest.body, getPostByIdData);
post = data;
} catch (error) {
// ...
}
return {
post,
}
}
}
從今天的範例來看 Nuxt plugin 其實滿好寫的,我們也看到可以根據專案需求另外擴充 axios 成為 plugin,尤其 API 的 request 和 response 通常都有一定的資料結構跟相關訊息,透過整合成 plugin 可以將許多重複處理的流程集中整合,讓 code 變得更簡潔。
在 Nuxt 中因為是 SSR ,所以畫面渲染的過程如果有遇到 window
、document
等前端資料就會出問題,因此明天會介紹 Nuxt 系列的最後一篇 client-only
!
P.s. 如果大大在使用 lara-validator 的過程中有 bug 或是建議增加甚麼功能歡迎 拍打餵食 ,我是說留言跟我說 XD